package com.tang.util;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.bson.Document;
import org.bson.types.ObjectId;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;

@Component("document")
public class MongoDBUtil {

    /**
     * java转化为document
     *
     * @param model
     * @return
     * @throws Exception
     */
    public Document javaBeanToDocument(Object model) throws Exception {
        Document document = new Document();
        if (null != model) {
            Field[] field = model.getClass().getDeclaredFields(); // 获取实体类的所有属性，返回Field数组
            for(int j = 0; j < field.length; j++) { // 遍历所有属性
                String names = field[j].getName(); // 获取属性的名字
                if ("serialVersionUID".equals(names)) {
                    continue;
                }
                String name = names.substring(0, 1).toUpperCase()
                        + names.substring(1); // 将属性的首字符大写，方便构造get，set方法
                String type = field[j].getGenericType().toString(); // 获取属性的类型
                if (type.equals("class java.lang.String")) { // 如果type是类类型，则前面包含"class "，后面跟类名
                    Method m = model.getClass().getMethod("get" + name);
                    String value = (String) m.invoke(model); // 调用getter方法获取属性值
                    document.append(names, value);
                    if (value == null) {
                        m = model.getClass().getMethod("set" + name,
                                String.class);
                        m.invoke(model, "");
                    }
                }
                if (type.equals("class java.lang.Integer")) {
                    Method m = model.getClass().getMethod("get" + name);
                    Integer value = (Integer) m.invoke(model);
                    document.append(names, value);
                    if (value == null) {
                        m = model.getClass().getMethod("set" + name,
                                Integer.class);
                        m.invoke(model, 0);
                    }
                }
                if (type.equals("class java.lang.Boolean")) {
                    Method m = model.getClass().getMethod("get" + name);
                    Boolean value = (Boolean) m.invoke(model);
                    document.append(names, value);
                    if (value == null) {
                        m = model.getClass().getMethod("set" + name,
                                Boolean.class);
                        m.invoke(model, false);
                    }
                }
                if (type.equals("class java.lang.Float")) {
                    Method m = model.getClass().getMethod("get" + name);
                    Float value = (Float) m.invoke(model);
                    document.append(names, value);
                    if (value == null) {
                        m = model.getClass().getMethod("set" + name,
                                Float.class);
                        m.invoke(model, false);
                    }
                }
                if (type.equals("class java.lang.Double")) {
                    Method m = model.getClass().getMethod("get" + name);
                    Double value = (Double) m.invoke(model);
                    document.append(names, value);
                    if (value == null) {
                        m = model.getClass().getMethod("set" + name,
                                Double.class);
                        m.invoke(model, false);
                    }
                }
                if (type.equals("class java.util.Date")) {
                    Method m = model.getClass().getMethod("get" + name);
                    Date value = (Date) m.invoke(model);
                    document.append(names, value);
                    if (value == null) {
                        m = model.getClass()
                                .getMethod("set" + name, Date.class);
                        m.invoke(model, new Date());
                    }
                }
            }

        }
        return document;
    }

    /**
     * json转化为document对象
     *
     * @param model
     * @return
     * @throws Exception
     */
    public Document jsonToDocument(String model) throws Exception {
        JSONObject json = JSONObject.parseObject(model);
        Set<String> keys = json.keySet();
        Document document = new Document();
        for(String key : keys) {
            document.append(key, json.getString(key));
        }
        return document;
    }

    /**
     * 更新时json转化为document对象
     *
     * @param model
     * @return
     * @throws Exception
     */
    public Map<String, Object> jsonToDocumentForUpdate(String model)
            throws Exception {
        JSONObject json = JSONObject.parseObject(model);
        Set<String> keys = json.keySet();
        Document document = new Document();
        Document filter = new Document();
        for(String key : keys) {
            if ("_id".equals(key)) {
                filter.append("_id", new ObjectId(json.getString("_id")));
            } else {
                document.append(key, json.getString(key));
            }
        }
        Document update = new Document();
        update.append("$set", document);
        Map<String, Object> map = new HashMap<>();
        map.put("filter", filter);
        map.put("update", update);
        return map;
    }

    /**
     * 删除时json转化为document对象
     *
     * @param model
     * @return
     * @throws Exception
     */
    public Document jsonToDocumentForDelete(String model) throws Exception {
        JSONObject json = JSONObject.parseObject(model);
        Set<String> keys = json.keySet();
        Document filter = new Document();
        for(String key : keys) {
            filter.append(key, new ObjectId(json.getString(key)));
        }
        return filter;
    }

    /**
     * json转化为document相关的列表对象
     *
     * @param model
     * @return
     * @throws Exception
     */
    public List<Document> jsonToDocumentList(String model) throws Exception {
        JSONArray json = JSONObject.parseArray(model);
        int size = json.size();
        List<Document> list = new ArrayList<>();
        for(int i = 0; i < size; i++) {
            JSONObject job = json.getJSONObject(i);
            Set<String> keys = job.keySet();
            Document document = new Document();
            for(String key : keys) {
                document.append(key, job.getString(key));
            }
            list.add(document);
        }
        return list;
    }

    /**
     * json转化为document对象（模糊查询）
     *
     * @param model
     * @return
     * @throws Exception
     */
    public Document jsonToDocumentLike(String model) throws Exception {
        JSONObject json = JSONObject.parseObject(model);
        Set<String> keys = json.keySet();
        Document document = new Document();
        for(String key : keys) {
            document.append(key, new Document("$regex", json.getString(key)));
        }
        return document;
    }

}
